'''
Created on Nov 25, 2012

@author: trananh
'''
import numpy

class Item(object):
    """
    A simple abstraction of a data item, which contains some data, a class
    label, and a prediction label (default to None).
    """
    
    def __init__(self, data=None, label=None, prediction=None, **kwargs):
        """
        Constructs a data item.
        """
        if data is None:
            self.data = list()
        else:
            self.data = [numpy.array(data, numpy.float)]
        self.label = label
        self.attributes = kwargs
        self.prediction = prediction
    
    def addData(self, newdata):
        self.data.append(numpy.array(newdata, numpy.float))

    def distance(self, other, featuresIdx=None):
        """
        Compares this item with another item and return the distance between them.
        By default, we'll use the Euclidean distance.
        
        PARAMETERS:
            other - the item to compare with.
            featuresIdx - specifies a subset of features (by indices) to be
                used rather than all of them.
        """
        if featuresIdx is None:
            featuresIdx = range(len(self.data))
        return numpy.linalg.norm(numpy.reshape(self.getFeatures(featuresIdx) \
                                               - other.getFeatures(featuresIdx), -1))
    
    def getFeatures(self, featuresIdx):
        """
        Retrieve the data corresponding to the specified features in a matrix, stacking
        features by rows.
        
        PARAMETER(S):
            featuresIdx - specifies which features to return.
        """
        results = self.data[featuresIdx[0]]
        for i in featuresIdx[1:]:
            results = numpy.vstack([results, self.data[i]])
        return results
        
    def __repr__(self):
        return '{ label : %s, attributes : %s, data : %s }' % \
            (self.label, self.attributes, self.data)
